api Rotations

    trait AnyQuaternion end
    
    trait Quaternion[\E\]
        extends { AnyQuaternion, Vector[\E,4\] }
    
        getter w(): E
        getter x(): E
        getter y(): E
        getter z(): E
        
        axis_angle(): (Vector[\E,3\],E)
        rotation_matrix[\T\](): Matrix[\T,3,3\]

        rotate[\T\](v: Vector[\T,3\]): Vector[\T,3\]
    end
    
    opr juxtaposition[\T extends Number\](me: Quaternion[\T\], other: Quaternion[\T\]): T
    
    quaternion[\T\](vec: Vector[\T,4\]): Quaternion[\T\] 
    quaternion[\T\](w:T, x:T, y:T, z:T): Quaternion[\T\] 
    quaternion[\T\](rotation_matrix: Matrix[\T,3,3\]): Quaternion[\T\] 
    quaternion[\T\](axis: Vector[\T,3\], angle: RR64): Quaternion[\T\]

    (** Returns the euler angles (%phi%, %omega%, %kappa%) *)
    rotation_matrix_to_euler_xyz(rotation_matrix: Matrix[\RR64,3,3\]): (RR64,RR64,RR64)

    (** Returns the euler angles (%phi%, %omega%, %kappa%) *)
    rotation_matrix_to_euler_yxz(rotation_matrix: Matrix[\RR64,3,3\]): (RR64,RR64,RR64)

    (** Returns the euler angles (%phi%, %omega%, %kappa%) *)
    rotation_matrix_to_euler_zxy(rotation_matrix: Matrix[\RR64,3,3\]): (RR64,RR64,RR64)

    (** Return the rotation matrix for the rotation about the x-axis *)
    rotation_x_axis(theta: RR64): Matrix[\RR64,3,3\]

    (** Return the rotation matrix for the rotation about the y-axis *)
    rotation_y_axis(theta: RR64): Matrix[\RR64,3,3\]

    (** Return the rotation matrix for the rotation about the z-axis *)
    rotation_z_axis(theta: RR64): Matrix[\RR64,3,3\]

    (** 
     * Creates a rotation matrix that represents the same rotation
     * through the sequence of euler angles, [%phi%, %theta%, %kappa%].  
     * The euler angles are defined according to the convention specified
     * in variable %sequence%. Sequence is a string containing any
     * combination of the characters 'x', 'y', and 'z' (though the
     * sequence must always be three characters long) that defines the
     * axes of rotation for %phi%, %theta%, and %kappa% respectively.  
     * For example, the sequence "XZY" would create a rotation of %phi%
     * degrees around the X axis, then %omega% degrees around the new Z
     * axis, and finally %kappa% degrees around the new Y axis.
     *
     * In matrix notation, this would rotate a vector %w_initial% as
     * follows:
     *
     * %w_final = kappa_y  omega_z  phi_x  w_initial%
     *)
    euler_to_rotation_matrix(phi: RR64, omega: RR64, kappa: RR64, sequence: String): Matrix[\RR64,3,3\]

    (** Quaternion variant of euler_to_rotation_matrix() *)
    euler_to_quaternion(phi: RR64, omega: RR64, kappa: RR64, sequence: String): Quaternion[\RR64\]

    (* Specific version optimized for Rxyz euler angles and quaternions *)
    euler_xyz_to_quaternion(phi: RR64, omega: RR64, kappa: RR64): Quaternion[\RR64\]

    quaternion_to_euler_xyz(q: Quaternion[\RR64\]): (RR64,RR64,RR64)

    axis_angle_to_quaternion[\T\](axis_angle: Vector[\T,3\]): Quaternion[\T\]
    axis_angle_to_matrix[\T\](rotation_vector: Vector[\T,3\]): Matrix[\T,3,3\]

    matrix_to_axis_angle[\T\](q: Matrix[\T,3,3\]): Vector[\T,3\]

    direct_cosine_matrix[\T\](v1: Vector[\T,3\], v2: Vector[\T,3\]): Matrix[\T,3,3\]

end Rotations (* api *)
